[#24] Trading widget for story page#72
Conversation
Fixes #24 - P5-2a: TradingWidget component with buy/sell tabs, amount input, and estimated cost/return from MCV2_Bond view functions - P5-2b: Buy flow — checks allowance, approves PLOT_TOKEN if needed, calls MCV2_Bond.mint() with 3% slippage protection - P5-2c: Sell flow — calls MCV2_Bond.burn() with 3% slippage protection - Shows tx state progression (approving → confirming → pending → done) - Extended lib/price.ts with mint/burn/approve/allowance ABIs - All addresses from lib/contracts/constants.ts, reserve label adapts to testnet (WETH) vs mainnet ($PLOT) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Summary
The UI scaffolding and state handling are reasonable, and CI is green, but the widget is currently built against Mint Club V2 function signatures that do not match the published MCV2_Bond contract interface. As written, the quote reads and trade writes will not execute against the real bond contract.
Findings
- [high] The estimate calls use
priceForNextMint(token, amount)/priceForNextBurn(token, amount), but Mint Club V2's publishedMCV2_Bondinterface exposes quote helpers under different signatures (priceForNextMint(token)and refund/reserve quote helpers), not the 2-arg selectors defined here. That means the widget is computing selectors from a made-up ABI and the live estimate calls will fail at runtime.- File:
src/components/TradingWidget.tsx:49 - Suggestion: Replace the custom estimate ABI with the real
MCV2_Bondquote/view functions from the deployed contract and wire the widget to those selectors.
- File:
- [high] The transaction ABI is also missing the receiver parameter. Mint Club V2's published
mint/burnsignatures take four arguments, including a receiver address, but this PR encodes only three args (token,amount, slippage bound). Those writes will target the wrong function selector and revert instead of trading.- File:
src/components/TradingWidget.tsx:93 - Suggestion: Update the ABI to the real
mint/burnsignatures and pass the connected wallet address as the receiver argument.
- File:
Decision
Requesting changes because the current contract calls do not match the real MCV2_Bond interface, so the trading widget is not functional yet.
project7-interns
left a comment
There was a problem hiding this comment.
REQUEST CHANGES — missing approval in sell flow.
Bug (blocking): src/components/TradingWidget.tsx:100-113 — The sell flow calls MCV2_Bond.burn() directly without first checking/approving the storyline token. MCV2_Bond needs approval to transfer the user's storyline tokens before burning. The buy flow correctly handles allowance/approve for PLOT_TOKEN, but the sell flow is missing the equivalent for the storyline token (tokenAddress).
Fix: mirror the buy flow's allowance check pattern — check allowance(address, MCV2_BOND) on tokenAddress, approve if insufficient, then call burn().
Minor (non-blocking):
lib/rpcis imported for the client-sidepublicClient, whilelib/price.tsuseslib/viem— verify these are intentionally separate (server vs client viem instances).- Price estimate query fires on every keystroke with no debounce — could generate excessive RPC calls during fast typing.
Adds required 4th `receiver` parameter to mint() and burn() ABI signatures and passes connected wallet address as receiver in both trade flows. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Summary
The receiver-parameter fix addresses one contract-call issue, but the sell flow is still not executable because it never approves the storyline token before calling MCV2_Bond.burn().
Findings
- [high] The sell path jumps straight to
burn()without checking or approving the user's allowance fortokenAddress. IfMCV2_Bondpulls storyline tokens viatransferFrombefore burning, every sell will revert for users who have not already approved the bond contract.- File:
src/components/TradingWidget.tsx:100 - Suggestion: Mirror the buy flow for sells: read
allowance(address, MCV2_BOND)ontokenAddress, prompt an approval transaction when needed, and only then callburn().
- File:
Decision
Requesting changes because the current sell path is not functional for first-time sellers.
project7-interns
left a comment
There was a problem hiding this comment.
REQUEST CHANGES — sell-side approval still missing.
The receiver parameter fix is good, but the original issue remains: the sell flow (lines ~100-113) calls MCV2_Bond.burn() without checking/approving the storyline token (tokenAddress) to MCV2_BOND. The bond contract calls transferFrom on the storyline token, which requires ERC-20 approval.
Please add the same allowance check + approve pattern used in the buy flow, but for tokenAddress instead of PLOT_TOKEN:
// Check storyline token allowance
const allowance = await publicClient.readContract({
address: tokenAddress,
abi: erc20Abi,
functionName: "allowance",
args: [address, MCV2_BOND],
});
if (allowance < parsedAmount) {
setTxState("approving");
const approveHash = await writeContractAsync({
address: tokenAddress,
abi: erc20Abi,
functionName: "approve",
args: [MCV2_BOND, parsedAmount],
});
await publicClient.waitForTransactionReceipt({ hash: approveHash });
}Mirrors the buy flow's approve pattern: checks storyline token allowance for MCV2_BOND and approves if insufficient before calling burn(). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
LGTM. Sell flow now correctly checks storyline token allowance and approves MCV2_BOND before burning — mirrors the buy flow pattern. Receiver parameter added to both mint/burn ABI signatures. Both flows are now complete: buy (approve PLOT_TOKEN → mint) and sell (approve storyline token → burn). Approved.
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Summary
The new sell-token approval step is correct, but there is still a blocking ABI mismatch on the quote path. Mint Club V2's published IMCV2_Bond interface exposes getReserveForToken(token, tokensToMint) and getRefundForTokens(token, tokensToBurn) for estimates, not priceForNextMint(token, amount) / priceForNextBurn(token, amount).
Findings
- [high] The widget's live estimate query is still wired to non-existent selectors, so quote reads will fail at runtime even after the receiver and approval fixes. The canonical interface published by Mint Club V2 defines
getReserveForTokenandgetRefundForTokensas the view functions for these estimates, while this PR continues to call custompriceForNextMint/priceForNextBurnentries.- File:
src/components/TradingWidget.tsx:46 - Suggestion: Replace the custom estimate ABI and query logic with the real
IMCV2_Bondview functions (getReserveForTokenfor buy quotes andgetRefundForTokensfor sell quotes), then apply slippage to those returned reserve/refund amounts.
- File:
Decision
Requesting changes because the widget still cannot fetch valid buy/sell estimates from the deployed bond contract.
Switch from custom priceForNextMint/priceForNextBurn to the real MCV2_Bond view functions: getReserveForToken and getRefundForTokens. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
LGTM. Estimate functions correctly updated to getReserveForToken/getRefundForTokens matching the real IMCV2_Bond interface. Consistent across lib/price.ts and TradingWidget. Approved.
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: APPROVE
Summary
The trading widget now uses the published Mint Club V2 quote functions, includes the required receiver parameter on trades, and handles approval for both buy and sell flows. The PR matches issue #24 and lint-and-typecheck is passing.
Findings
- none
Decision
Approving because the story-page trading widget is now wired to the canonical IMCV2_Bond interface with working slippage and approval handling for both directions.
Summary
priceForNextMint/priceForNextBurn)MCV2_Bond.mint()with 3% slippage protectionMCV2_Bond.burn()with 3% slippage protectionlib/contracts/constants.tsFixes #24
Test plan
npm run lintandnpm run typecheckpass🤖 Generated with Claude Code